from django.shortcuts import render
from utils.permission import *
from .serializers import *  # 所有的序列化器类
from rest_framework.permissions import IsAuthenticated
from rest_framework.viewsets import ModelViewSet  # 视图集模块
from fdfs_client.client import Fdfs_client, get_tracker_conf  # FastDFS
from config.fastdfsConfig import FASTDFS_SERVER_DOMAIN  # 部署代理的位置
import logging  # 日志器
from rest_framework.status import HTTP_404_NOT_FOUND, HTTP_400_BAD_REQUEST, HTTP_500_INTERNAL_SERVER_ERROR,HTTP_403_FORBIDDEN
from rest_framework.decorators import action  # 行为路由装饰器
from rest_framework.response import Response  # 响应
from rest_framework.mixins import CreateModelMixin # 创建
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet  # 只读

from drfstudy22.settings import alipay  # 支付宝对象

# 创建日志器
logger = logging.getLogger(__name__)  # 创建一个记录邮箱发送的日志器

tracker_path = get_tracker_conf('utils/fastdfs/client.conf')  # tracker配置文件路径
client = Fdfs_client(tracker_path)  # 客户端对象


# Create your views here.
# 商品分类视图集
class ClassificationViewSet(ModelViewSet):
    queryset = Classification.objects.filter(is_delete=False)  # 查询集
    # serializer_class = ClassificationSerializer  # 需要使用的序列化器
    serializer_class = ParentClassificationSerializer  # 需要使用的序列化器
    # 要求用户先进行身份验证，才能够访问该视图类
    permission_classes = [IsAuthenticated]

    # 创建
    @wrap_permission(TeacherPermission)
    def create(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

    # 修改
    @wrap_permission(TeacherPermission)
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)

    # 删除
    @wrap_permission(TeacherPermission)
    def destroy(self, request, *args, **kwargs):
        return ModelViewSet.destroy(self, request, *args, **kwargs)

    # 根据不同等级去展示不同等级的数据
    @action(methods=['get'], detail=True)
    def commodity(self, request, pk):
        try:
            classification = Classification.objects.filter(is_delete=False).get(id=pk)
        except Classification.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)
        # 一级分类
        classification_attr = 'classification1'
        classification_name = classification.name  # 分类名，一级分类名
        if classification.parent:
            classification_attr = 'classification2'
            classification_name = f'{classification.parent.name}--{classification.name}'

        data = getattr(classification,classification_attr).filter(is_delete=False, status=1)
        return Response({
            'classification':classification_name , # 分类的名字
            'commodity':CommoditySerializer(data,many=True).data
        })



# 商品视图集
class CommodityViewSet(ModelViewSet):
    queryset = Commodity.objects.filter(is_delete=False, status=1)  # 查询集
    # serializer_class = ClassificationSerializer  # 需要使用的序列化器
    serializer_class = CommoditySerializer  # 需要使用的序列化器
    # 要求用户先进行身份验证，才能够访问该视图类
    permission_classes = [IsAuthenticated]

    # 自定义查询集
    def get_queryset(self):
        if self.action in ['list', 'retrieve']:
            return Commodity.objects.filter(is_delete=False, status=1)  # 查询集
        return self.queryset

    # 创建
    @wrap_permission(TeacherPermission)
    def create(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

    # 修改
    @wrap_permission(TeacherPermission)
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)

    # 删除
    @wrap_permission(TeacherPermission)
    def destroy(self, request, *args, **kwargs):
        return ModelViewSet.destroy(self, request, *args, **kwargs)

    # 商品图片上传
    @action(methods=['post'], detail=True)
    def img(self, request, pk):
        try:
            commodity = self.get_queryset().get(id=pk)  # 哪个商品
        except Commodity.DoesNotExist:  # 没获取到数据
            return Response(status=HTTP_404_NOT_FOUND)

        # 得到上传的头像
        file = request.FILES.get('file')
        if not file or file.content_type not in ('image/jpeg', 'image/png', 'image/gif'):
            return Response(status=HTTP_400_BAD_REQUEST)

        try:
            images_ext_name = file.name.split('.')[-1]
        except Exception as e:
            logger.info('图片扩展名异常：%s' % e)
            images_ext_name = 'png'

        # 上传图片
        try:
            upload_res = client.upload_by_buffer(file.read(), file_ext_name=images_ext_name)
        except Exception as e:
            logger.error('图片上传异常：%s' % e)
            return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)

        else:
            if upload_res.get('Status') != 'Upload successed.':
                logger.warning('图片上传失败')
                return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)

            image_name = upload_res.get('Remote file_id').decode()  # 解码
            image_url = FASTDFS_SERVER_DOMAIN + image_name  # 完整的图片的路由地址
            # 哪个商品的图片
            CommodityImg.objects.create(src=image_url,commodity=commodity)

            return Response({'data': image_url})


    # 优选商品
    @action(methods=['get'], detail=False)
    def optimization(self, request):
        queryset = self.get_queryset().order_by('-comments').order_by('-create_time')
        return Response(self.get_serializer(queryset[:5],many=True).data)


# 购物车视图集
class ShoppingCartViewSet(ModelViewSet):
    serializer_class = ShoppingCartSerializer # 需要使用的序列化器
    # 要求用户先登录，才能够访问该视图类
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        return self.request.user.shoppingcart_set.all()

    # 创建
    @auto_user
    def create(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

    # 修改 要求是该作者才能够修改该作者的文章
    @update_auto_user
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)

    # 删除
    @destroy_auto_user
    def destroy(self, request, *args, **kwargs):
        return ModelViewSet.destroy(self, request, *args, **kwargs)

# 订单视图集
class OrderViewSet(ReadOnlyModelViewSet,CreateModelMixin):
    serializer_class = OrderSerializer # 需要使用的序列化器

    def get_queryset(self):
        return self.request.user.order_set.all()

    # 订单状态修改的行为路由，需要把待支付改成代发货状态
    @action(methods=['put'], detail=False)
    def status(self, request):
        # 支付宝请求后会返回能够直接使用的参数
        query_dict = request.query_params  # 支付宝地址栏参数
        data = query_dict.dict()  # 转字典

        # 修改
        try:
            sign = data.pop('sign')
        except KeyError:
            return Response(status=HTTP_400_BAD_REQUEST)

        # 验证支付账号是否符合校验
        res = alipay.verify(data,sign)
        if not res:
            return Response(status=HTTP_403_FORBIDDEN)

        # 得到订单编号，支付宝交易号
        order_id = data.get('out_trade_no')  # 订单编号
        trade_no = data.get('trade_no')  # 支付宝交易号

        # 保存支付信息，修改订单状态
        with transaction.atomic():
            save_point = transaction.savepoint()
            try:
                Payment.objects.create(order_id=order_id,trade_id=trade_no)
                # 把支付改成代发货
                Order.objects.filter(order_id=order_id,status=1).update(status=2)
            except Exception as e:
                transaction.savepoint_rollback(save_point)
                raise serializers.ValidationError(e)
            else:
                transaction.savepoint_commit(save_point)
        return Response({'order_id':order_id,'trade_id':trade_no})


# 支付宝凭证视图集
class PaymentViewSet(ReadOnlyModelViewSet):
    queryset = Payment.objects.all()  # 查询集
    serializer_class = PaymentSerializer # 需要使用的序列化器

    # 支付结算后的行为方法
    @action(methods=['get'], detail=True)
    def pay(self, request,pk):
        try:
            # 获取订单信息，包装当前登录的这个用户的订单，并且是待支付状态
            order = Order.objects.get(order_id=pk,user=request.user,status=1)
        except Order.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)

        # 调用支付方法，通过支付宝处理订单信息
        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no = order.order_id,  # 订单号
            total_amount = str(order.total_amount), # 支付金额
            subject=f'子冧项目支付{order.order_id}',
            return_url='http://localhost:8080/home/order/success'  # 前端调用的支付接口
        )

        # 支付宝网关地址
        pay_url = 'https://openapi-sandbox.dl.alipaydev.com/gateway.do?'+order_string

        return Response({'pay_url':pay_url})


